﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using Data.Models;

namespace Data.Infrastructure
{
    public abstract class RepositoryBase<T> where T : class
    {
        private QuanLySanXuatContext dataContext;
        private readonly IDbSet<T> dbset;
        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        protected QuanLySanXuatContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }
        public virtual void Add(T entity)
        {
            dbset.Add(entity);
        }

        public virtual void AddRange(IEnumerable<T> entities)
        {
            foreach (var item in entities)
            {
                Add(item);
            }
        }

        public virtual void UpdateRange(IEnumerable<T> entities)
        {
            foreach (var item in entities)
            {
                Update(item);
            }
        }
        public virtual void Update(T entity)
        {
            var entry = dataContext.Entry<T>(entity);

            // Retreive the Id through reflection
            var pkey = dbset.Create().GetType().GetProperty("ID").GetValue(entity);

            if (entry.State == EntityState.Detached)
            {
                var set = dataContext.Set<T>();
                T attachedEntity = set.Find(pkey);  // access the key
                if (attachedEntity != null)
                {
                    var attachedEntry = dataContext.Entry(attachedEntity);
                    attachedEntry.CurrentValues.SetValues(entity);
                }
                else
                {
                    entry.State = EntityState.Modified; // attach the entity
                }
            }
        }
        public virtual void Delete(T entity)
        {
            dbset.Remove(entity);
        }
        public virtual void Delete(Expression<Func<T, bool>> where)
        {
            IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                dbset.Remove(obj);
        }
        public virtual T GetById(int id)
        {
            return dbset.Find(id);
        }
        public virtual T GetById(string id)
        {
            return dbset.Find(id);
        }
        public virtual IEnumerable<T> GetAll()
        {
            return dbset.ToList();
        }
        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).ToList();
        }
        public T Get(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).FirstOrDefault<T>();
        }
        
        public IEnumerable<T> ExecWithStoreProcedure(string query, params object[] parameters)
        {
            
            return DataContext.Database.SqlQuery<T>(query, parameters);
        }
        
    }
}
